package com.jeeplus.modules.api.utils.alipay;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.google.common.collect.Maps;
import com.jeeplus.common.json.AjaxJson;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class AlipayUtils {
	private static final Logger logger = LoggerFactory.getLogger(AlipayUtils.class);

//	private static final String APP_ID = "2019080666153231"; // 正式版
	private static final String APP_ID = "2021002146689823"; // 正式版
	// 应用私钥 正式
//	private static final String APP_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCTjMbUvK7BV90jR6Pbx5zaCuc021vTObhoJztV6DR95WKgHNh3GlZTZQ3nUkMowZiaRffy557PUylWRrFp7tuhZ4A9U9ugAmUb8nn0sxwPuiQEg1xgIDICg+iPL4rcOKqw3uyAvkBW18ooBsQOY7VeoO9TNXm3G+9nY08X7RPDB/yOoA+RvUX6gwlW4zdd9DMK8EdFGXbjNYQe1qJFAvLYNWzJyWtZvIj8IITki+1Ytzg3hkPnOIwm8zbfn98FKWpfou7lQEY4rB2+LDpngT8H5+pDUAwxWJxriNopNnfDARIHvrzyTnl7dF6za85IOApW4OSAzvPgR/SM617Qi7ZFAgMBAAECggEAZ4BU6V4B6DZONTVHyB/Z80m6reVCIIVYyhbbFIPybm2+JTqWzdV3wMAeZKnb2ncTKQTzzTyUtjJLyO2F/h1Di5Ei7+InKbMEYfpRekk54f5czZ2n6vYqnoERXX+oFJrbgX6ewCC02TY95J36YW2oCF00BFZ6ruu1n/yVut7fAetCgI5GT6VNP0ArBvTZ6/kSe4l3B8v1WIGKU3oJQC68rK8c5gKRVYG1AfySsyNrcoeOG+saJhHRYrzmlGS3cjrdYMQuN63CVW2ahzuivabkHyDILk5dL2bqjy5WTQmPVx7u8tktZNe1rYr3PCwB6v6tmcHPi9++vJNP/OUVcoumcQKBgQDUzCKqs/OEX9NTCqA6faDeDMmfzeQj2xlPJEu4qX11oQIFYrpQGZsZy7/G2S2ZGUf/TX+1m3toDGTehWjJVvsMthqnp73udvYiBc+Y8ulvcR/gI0qH7zs/dQK9Cs1NANlFQmdP14BNgQcLd49lxiZ8Gq/P5Cgu25v4mGUwQutqZwKBgQCxgX0cWjcYsbXTK6FcEpUM167v5SNjFsXgtXe1OlxG0x97VPmjNpSI2c+IEzg0AX6tXihhEn5locsrVB2ro0D3mlUenMyd50QSdSuMk77v65M7ESwwGHu06bu+CGHWLbpxdUOlKH98Bopu+GVcr5gcsy9briQMeQtWf+Onkn+GcwKBgQDBsgakJyS0C52J6xQp6YxyUmV8xqaxVI/XEAy0y+JdHe9/A3zfyE77zhCEac8tmmuEogBrSFmuPgna2sik7D2cNm5QyUkDNNmZ4nwylnmRbQE8viLrVQEzI8kYVirFus4KUwVDEb/BzH6jG3M1ioYhVRFPRDinXlK8l8sTgPZUZQKBgAKlbIkMqz+Z/pzsTJaDzGcJnBkFcHacs0x7SBKSkSeZJCIBjUsqmCJGJPrhVngoAYxyF+YCkZHQTKgTs/GIGILYcSZorgA4n2IrDwAkf7cx6tr5kZAR/V4gEeVuWI8J1Xq1hdGjfesKaevnlhNApuLepPkX6n+pGksq0uj/nRkTAoGAaOHIyLxDPzbzM3TCYHma3kuXKvClI6vfUODlemS7Z3WRG3j7TjaM++AGsGdRHviPsEAiorP9jaA/rQ6hnQTtYOMedSoVW/tMxfkMmOLtT50bRgod62j6ykrG2n27pPTwb9J7QCatyzy5xA6S2OQsmxfRC7doW0m9ohFJ9HcCdTI=";
	private static final String APP_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCzhwQ7Jfbi60F5pLcNC5HHvTLGf6plH/3l+pAabP/vDmG+DcMD2+YC13DP5OuJQvav+/Q3UZ//YVsFN+XmJ/9JBkd5+KTlcQUReSsVxwSa+3DSbQlZ354lZbxD8erarVoP9h/QEwCGAGUOVPe0LshhTfgPvrsRbd4W735rnfVPpWQbQdxBjK0yf6MLRSxlHtaReGxx4XMmnC9zDvEgo4wV3YRmkTLLiUzQkAH+H8Jglr/B9+zrnQGw97fGTDEFS/xIxL7JMoWmAj4vMv4RhsU7nJW9EEkmWJfwSOrl6GWh+PC8T/WngIjYQ8C/0lIzcxqsk55Ju7rjFTcmuxtGQFOLAgMBAAECggEAZ93836/GWGFeH1/iHGUOMe7P2rJwRlOtFQrTpsZbiNbcTBYwNyJZwFkfRtieQWsByK3QDNVn6VxNSgaeN3v6oihE4FewJ6MtGH/vIoljq7s/+i7lkx7io6ZptzHW/DABhGyU2VC1I9JEpXcZXSEYA9wVYh6qopnbPY/Qp7ja/fmtYP9neDS2fHwDhE0UyLtOtbYfYoe5y9u17jre/eGUQdlVSb33MfXbVfRUbzIFYvwdgIRvpPzND3s2XHcWksmC1uDLfCtNgRFR7QS/FayrpEMhIQwNtBOmOLqKj4XCZG5mwn1aLAq8/wTvdYS444r8l1ntRIU0yTh/1iR54HCEYQKBgQDe5gVWRu9FoBJhCjjbCDwFQSH/3SmhartGZNKDjQdk//0/WUi+IzN1bH7Hc6s5QhAMfheD4PdPsU2VJnYqdk+uwWhXoUEipfc+4kb0K1Wvm340jxvpOqtY9IGBEKBrW8VYqa9tVIWOYLEu9lFzd2TwjkUt8DZg9264JigL+b92sQKBgQDOMCWt+KRlAUqPuDHGapkNtOdVNZLrbS9z+glgtbHkUOvlIa2Ivnkyi50V0L4xB/4jqwcdt88aPAyIsnJ3Z8rBZZsAUOm50rbHKlzkCkmSAqxUQXqciRZwxiAssnKS8Js1mgCfmB4E1RiUG0p5/E+ghMrCKZTYFaZr5BLqGts0+wKBgQCLrh+YEnms6wO5dfttHvrl3AwfWAvXkJftJA9bysvgeh7MTPot1MdRhXzpJk4dYo3GFlpMFXVFpnlUxzZzo5KJk7/8chvsR47qBEisiF943Xs4GppGDLMF2qsxIyc0P90qk6NQYxASyfsez9L5Bc/mg3FMuWSKXWQv2BFud8KI8QKBgQCPBFJ+c6MD9HtVaPwNls8G9N4o+nooFpn9pgdvL1hu97pIOq311biXWMPi5+GkfNjIwM60zFQ47EH9Z1mCfVnj/6gd9gHIxOHHEBlSi9gwEO6bmreDcItCOgsDNdvHFGF0MpgQGyFnVLAxuyRTrLFGtBU3zEPUBmBjIdYE0BAQlQKBgCG2ptcBuV2d2i5WhinF3lHR1dVbY4/LK13Jl61bZZx+XuPDyezrJ2c2/oc32gCr/1WAtXvgvSLbvdYLu/KVe/ylhRe6ECUFz8QCW/K9ApXyWFV+TmzVk6nFIPUEU6EavisRcuBkOxpN7nBZON7LVv5N1KuAA98W5MCVYM9WVT1P";
	public static final String CHARSET = "UTF-8";
	// 支付宝公钥 正式
//	private static final String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyoVz+WRY8+kZ63nxlwhxPmjQTPgUMXYR4HjTzdgNM+muU3O8Ceu5I3jsY4p5p7Mn0pXJmXO4XBd79SaiGrE7AnTX+V3O/9EqawWir6kcniXhUN4gCmsLubPo62hes32pv66uZ9+lACTQkUKXkkT5f2GdHpZ3J1WIuidrpwPyTRY8BjaRgwyxVvMMidI6TDXCPRIbtxwW7yT9n/zSPkFDKUNzqqTRoWqKkTB2jv97ADNqveHjcrmnwoggJNhIvUmLinFlOVWk0yWyyj/F13LIOhL7DFFixLGQjdvgzkLtwPom9cuBEH17fiG2EWUCe2ldM3LEkdAnR9Ui6wwwd8KsCwIDAQAB";
	private static final String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAreIjOwnUzFinJiPD84hw0mCHhWO5ISjimVP81mHGU9uUbO2JbiKJcv0zsT1LQcRv+ZhttXhUqdh7gODilkWVuJfSbNUcuNSoOEiqb1sz9y9qVshxTxG9P4I0abQTeHT9+ZWl1yhIIVFvbZzXj1Em0w9fZg3v/7R2VPGtFQjJ6lDBjkje0vUi8wqh+zU5ThPm2n9lmYDITP0vYdpbIhdKfeH+BcEYbf9mA6DPSSb1LH7Nm0ECY2JStzmMkScI7rnh+4AndkAoSTf/1HiBIUCnpsNnjjtl4vxH18Fybo8Zra2u9PF8vtjPTtsyBdd1Mncx6Aa9UR1xP2NDa6DMPj7UeQIDAQAB";

	private static final String SIGNTYPE = "RSA2";
	private static final String NOTIFYURL = "http://139.196.206.217/api/aliPayNotify";// "商户外网可以访问的异步地址"
																									// 回调地址不可以带参数
	private static final String RETURNURL = "http://139.196.206.217/api/aliPayNotify";// 成功后返回的页面地址
	private static final String TIMEOUT_EXPRESS = "30m";
	private static final String URL = "https://openapi.alipay.com/gateway.do"; // 正式
	public static final String app = "1";
	public static final String h5 = "2";
	public static final String pc = "3";

	/**
	 * 根据授权码获取支付宝用户信息
	 * @param code
	 * @return
	 */
	public static Map<String, String> getAccessTokenAndUserId(String code) {
		Map<String, String> map = Maps.newHashMap();
		map.put("result", "1");
		try {
			AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, SIGNTYPE);
			// 使用auth_code获取access_token与user_id
			AlipaySystemOauthTokenRequest requests = new AlipaySystemOauthTokenRequest();
			requests.setCode(code);
			requests.setGrantType("authorization_code");
			AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(requests);
			if (oauthTokenResponse.isSuccess()) {
				AlipayUserInfoShareRequest requestUser = new AlipayUserInfoShareRequest();
				AlipayUserInfoShareResponse userinfoShareResponse = alipayClient.execute(requestUser, oauthTokenResponse.getAccessToken());
				if (userinfoShareResponse != null) {
					String userId = userinfoShareResponse.getUserId();// 用户ID
					String nickName = userinfoShareResponse.getNickName();// 用户昵称
					String avatar = userinfoShareResponse.getAvatar();// 用户头像
					map.put("userId", userId);
					map.put("nickName", nickName);
					map.put("avatar", avatar);
					map.put("result", "0");
				}
			}
		} catch (Exception e) {
			map.put("resultNote", "授权失败");
			logger.error("支付宝获取授权信息失败： " + e.getMessage());
		}
		return map;
	}

	/**
	 * 创建支付宝订单
	 * 
	 * @param subject
	 *            订单标题
	 * @param body
	 *            商品描述
	 * @param price
	 *            价格
	 * @param orderid
	 *            支付宝订单编号
	 * @param type
	 *            1-APP 2-H5
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public static String createOrder(String subject, String body, String price, String orderid, String type,String passbackParams, String aliAppId, String aliUrl, String aliPublicKey, String aliPrivateKey, String aliNotifyUrl) throws UnsupportedEncodingException {
		return createOrder(subject, body, price, orderid, type, RETURNURL,passbackParams, aliAppId, aliUrl, aliPublicKey, aliPrivateKey, aliNotifyUrl);
	}

	/**
	 * 创建支付宝订单
	 * 
	 * @param subject
	 *            订单标题
	 * @param body
	 *            商品描述
	 * @param price
	 *            价格
	 * @param orderid
	 *            支付宝订单编号
	 * @param type
	 *            1-APP 2-H5
	 * @param returnUrl
	 *            返回页面路径
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public static String createOrder(String subject, String body, String price, String orderid, String type, String returnUrl,String passbackParams, String aliAppId, String aliUrl, String aliPublicKey, String aliPrivateKey, String aliNotifyUrl) throws UnsupportedEncodingException {
		// 实例化客户端
		AlipayClient alipayClient = new DefaultAlipayClient(aliUrl, aliAppId, aliPrivateKey, "json", CHARSET, aliPublicKey, SIGNTYPE);
		// 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
		AlipayRequest request = new AlipayTradeAppPayRequest();
		String productCode = "QUICK_MSECURITY_PAY";
		if (h5.equals(type)) {
			request = new AlipayTradeWapPayRequest();
		} else if (pc.equals(type)) {
			request = new AlipayTradePagePayRequest();
			productCode = "FAST_INSTANT_TRADE_PAY";
		}
		// SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		model.setBody(body);
		model.setSubject(subject);
		model.setOutTradeNo(orderid);// 更换为自己的订单编号
		model.setTimeoutExpress(TIMEOUT_EXPRESS);
		model.setTotalAmount(price);// 订单价格
		model.setProductCode(productCode);
		model.setPassbackParams(URLEncoder.encode(passbackParams,"UTF-8"));
		request.setBizModel(model);
		request.setNotifyUrl(aliNotifyUrl);// 回调
		request.setReturnUrl(StringUtils.isNotBlank(returnUrl) ? returnUrl : aliUrl);
		String orderStr = "";
		try {
			// 这里和普通的接口调用不同，使用的是sdkExecute
			if (h5.equals(type) || pc.equals(type)) {
				orderStr = alipayClient.pageExecute(request).getBody();
			} else {
				orderStr = alipayClient.sdkExecute(request).getBody();
			}
			logger.debug("支付宝返回数据：" + orderStr);
		} catch (AlipayApiException e) {
			logger.error("生成支付宝订单异常:" + e.getMessage());
			throw new RuntimeException("生成支付宝订单异常:" + e.getMessage());
		}
		return orderStr;
	}

	/**
	 * 退款
	 * 
	 * @param out_trade_no
	 *            订单号 订单支付时传入的商户订单号
	 * @param refund_amount
	 *            退款金额 该金额不能大于订单金额,单位为元，支持两位小数
	 * @return
	 */
	public static String refund(String out_trade_no, String refund_amount, String aliUrl, String aliAppId, String aliPublicKey, String aliPrivateKey) {
		AlipayClient alipayClient = new DefaultAlipayClient(aliUrl, aliAppId, aliPrivateKey, "json", "UTF-8", aliPublicKey, SIGNTYPE);
		AlipayTradeRefundRequest requests = new AlipayTradeRefundRequest();
		AlipayTradeRefundModel bizModel = new AlipayTradeRefundModel();
		bizModel.setOutTradeNo(out_trade_no);
		// bizModel.setTradeNo(tradeNo);
		bizModel.setRefundAmount(refund_amount);

		requests.setBizModel(bizModel);

		AlipayTradeRefundResponse response;
		String result = "";
		try {
			response = alipayClient.execute(requests);
			result = response.getBody();
			logger.debug("支付宝退款结果：" + result);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 获取支付宝异步返回值
	 * 
	 * @param request
	 * @return
	 */
	public static JSONObject getReceiveMap(HttpServletRequest request) {
		// 获取支付宝POST过来反馈信息
		Map<String, String> params = new HashMap<String, String>();
		Map<String, String[]> requestParams = request.getParameterMap();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = iter.next();
			String[] values = requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			// 乱码解决，这段代码在出现乱码时使用。
			// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
			params.put(name, valueStr);

		}
		// Map<String,Object> result=new HashMap<>();
		JSONObject result = new JSONObject();
		result.putAll(params);
		result.put("signVerified", false);// 判断验签是否成功
		// 切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
		// boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String
		// publicKey, String charset, String sign_type)
		try {
			logger.debug("------支付宝异步通知参数-------" + params.toString());
			boolean flag = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGNTYPE);
			logger.debug("------支付宝异步签名认证-------" + flag);
			result.put("signVerified", flag);
		} catch (AlipayApiException e) {
			logger.error("支付宝异步回调核对信息失败:" + e.getMessage());
		}
		return result;
	}

	//支付宝打款
	/**
	 * 向支付宝个人账号打款
	 * @param outBizNo--商户端的唯一订单号
	 * @param money--金额
	 * @param identity--参与方的唯一标识
	 * @param name--参与方真实姓名
	 * @return
	 * @throws AlipayApiException
	 */
	public static AjaxJson dakuang(String outBizNo, String money, String identity, String name, String txAppId, String txPrivateKey, String txPublicKey)  {
		AjaxJson j = new AjaxJson();
		try {
			j.setCode(0);
			AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", txAppId, txPrivateKey, "json", "UTF-8", txPublicKey, "RSA2");
			AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
			request.setBizContent("{" +
					"\"out_biz_no\":\"" + outBizNo +"\"," +
					"\"payee_type\":\"ALIPAY_LOGONID\"," +
					"\"payee_account\":\"" + identity +"\"," +
					"\"payee_real_name\":\"" + name +"\"," +
					"\"amount\":\"" + money +"\"" +
					"}");
			AlipayFundTransToaccountTransferResponse response = alipayClient.execute(request);
			logger.info("调用单笔转账到支付宝账户接口结果:{}", ReflectionToStringBuilder.toString(response));
			if(response.isSuccess() && "10000".equals(response.getCode()) && response.getOutBizNo().equals(outBizNo)){
				j.setSuccess(true);
				j.setMsg("转账成功！");
			} else {
				j.setSuccess(false);
				j.setMsg(response.getSubMsg());
				//如果调用alipay.fund.trans.toaccount.transfer掉单时，
				//或返回结果code=20000时，或返回结果code=40004，sub_code= SYSTEM_ERROR时，
				//请调用alipay.fund.trans.order.query发起查询，
				//如果未查询到结果，请保持原请求不变再次请求alipay.fund.trans.toaccount.transfer接口。
				if("20000".equals(response.getCode()) || "40004".equals(response.getCode()) || "SYSTEM_ERROR".equals(response.getSubCode())){
					j.setCode(1);
				}
			}
		} catch (Exception e) {
			j.setSuccess(false);
			j.setCode(2);
			j.setMsg("单笔转账到支付宝账户处理异常");
			logger.error("调用单笔转账到支付宝账户接口处理异常{}", e);
		}
		return j;
	}
}
